//! Helper functions for declaration parsing

use super::super::{parse_expression, parse_type, Parser};
use crate::ast::decl::GenericParam;
use crate::ast::types::Type;
use crate::error::{CompilerError, Result};
use crate::lexer::token::Token;

/// Parse block
pub fn parse_block(parser: &mut Parser) -> Result<crate::ast::Block> {
    // Note: LeftBrace is already consumed by the caller
    let mut statements = Vec::new();

    while !parser.check(&Token::RightBrace) {
        if let Some(stmt) = super::super::stmt_parser::parse_statement(parser)? {
            // Check if this is a terminating statement (return, break, continue)
            let is_terminating = matches!(
                stmt,
                crate::ast::stmt::Statement::Return(_)
                    | crate::ast::stmt::Statement::Break(_)
                    | crate::ast::stmt::Statement::Continue(_)
            );

            statements.push(stmt);

            // If we encountered a terminating statement, stop parsing
            // Skip any remaining statements until we reach the closing brace
            if is_terminating {
                // Consume all tokens until we find the closing brace
                while !parser.check(&Token::RightBrace) && !parser.is_at_end() {
                    parser.advance()?;
                }
                break;
            }
        } else {
            break;
        }
    }

    parser.expect(&Token::RightBrace)?;

    Ok(crate::ast::Block {
        statements,
        location: parser.current_location(),
    })
}

/// Parse attributes
pub fn parse_attributes(parser: &mut Parser) -> Result<Vec<crate::ast::decl::Attribute>> {
    let mut attributes = Vec::new();

    while parser.consume(&Token::At)? {
        if let Some(Token::Identifier(attr_name)) = parser.peek().map(|t| &t.token) {
            let name = attr_name.clone();
            parser.advance()?;

            let mut arguments = Vec::new();

            if parser.consume(&Token::LeftParen)? {
                if !parser.check(&Token::RightParen) {
                    loop {
                        if let Some(arg) = parse_expression(parser)? {
                            arguments.push(arg);
                        }

                        if !parser.consume(&Token::Comma)? {
                            break;
                        }
                    }
                }
                parser.expect(&Token::RightParen)?;
            }

            attributes.push(crate::ast::decl::Attribute {
                name,
                arguments,
                location: parser.current_location(),
            });
        }
    }

    Ok(attributes)
}

/// Parse a `where`-clause and merge its bounds into existing generic parameters.
///
/// Syntax (per design docs, simplified to use Type directly):
///   where T: Bound1 + Bound2, U: Bound3
///
/// For each predicate, all parsed bounds are appended into the corresponding
/// `GenericParam.constraints`. This is intentionally "just syntactic sugar" and
/// does not introduce new AST nodes.
pub fn parse_where_clause_for_generics(
    parser: &mut Parser,
    generics: &mut Vec<GenericParam>,
) -> Result<()> {
    // No `where` present: nothing to do.
    if !parser.consume(&Token::Where)? {
        return Ok(());
    }

    loop {
        // Left-hand side: generic parameter name
        let param_name = match parser.peek().map(|t| &t.token) {
            Some(Token::Identifier(name)) => {
                let name = name.clone();
                parser.advance()?;
                name
            }
            _ => {
                return Err(CompilerError::syntax(
                    parser.current_location().line,
                    parser.current_location().column,
                    "Expected type parameter name in where clause",
                ));
            }
        };

        // Colon after parameter name
        parser.expect(&Token::Colon)?;

        // Right-hand side: one or more bounds separated by '+'
        let mut bounds: Vec<Type> = Vec::new();
        loop {
            if let Some(bound_ty) = parse_type(parser)? {
                bounds.push(bound_ty);
            } else {
                return Err(CompilerError::syntax(
                    parser.current_location().line,
                    parser.current_location().column,
                    "Expected type in where clause bound",
                ));
            }

            if !parser.consume(&Token::Plus)? {
                break;
            }
        }

        // Merge bounds into the matching generic parameter
        if let Some(generic) = generics.iter_mut().find(|g| g.name == param_name) {
            generic.constraints.extend(bounds);
        } else {
            return Err(CompilerError::syntax(
                parser.current_location().line,
                parser.current_location().column,
                format!("Unknown type parameter '{}' in where clause", param_name),
            ));
        }

        // Multiple predicates are separated by commas
        if !parser.consume(&Token::Comma)? {
            break;
        }
    }

    Ok(())
}
